<template>
  <div class="ai-customer-service">
    <!-- 聊天按钮 -->
    <transition name="bounce">
      <div 
        v-show="!isOpen" 
        class="chat-button"
        :class="{ 'is-dragging': isDragging }"
        :style="buttonStyle"
        @mousedown="handleMouseDown"
        @touchstart="handleTouchStart"
        title="AI智能客服 (可拖拽)"
      >
        <i class="bi bi-robot"></i>
        <div class="pulse-ring" v-if="!isDragging"></div>
      </div>
    </transition>

    <!-- 聊天窗口 -->
    <transition name="slide-fade">
      <div v-show="isOpen" class="chat-window">
        <!-- 聊天窗口头部 -->
        <div class="chat-header">
          <div class="header-content">
            <i class="bi bi-robot"></i>
            <span class="header-title">AI智能客服</span>
          </div>
          <div class="header-actions">
            <button 
              class="minimize-btn" 
              @click="toggleChat"
              title="最小化"
            >
              <i class="bi bi-dash-lg"></i>
            </button>
            <button 
              class="close-btn" 
              @click="closeChat"
              title="关闭"
            >
              <i class="bi bi-x-lg"></i>
            </button>
          </div>
        </div>

        <!-- 聊天内容区域：支持两种模式 rag/api -->
        <div class="chat-content">
          <!-- RAG 模式：内嵌 iframe -->
          <template v-if="mode === 'rag'">
            <iframe
              v-if="isOpen"
              :src="chatUrl"
              frameborder="0"
              class="chat-iframe"
              @load="onIframeLoad"
              @error="onIframeError"
              allow="microphone; camera"
            ></iframe>
            <div v-if="isLoading" class="loading-overlay">
              <div class="loading-spinner">
                <i class="bi bi-arrow-repeat"></i>
                <span>正在连接智能客服...</span>
              </div>
            </div>
            <div v-if="hasError" class="error-overlay">
              <div class="error-message">
                <i class="bi bi-exclamation-triangle"></i>
                <p>连接失败</p>
                <small>请检查RAGflow服务是否正常运行</small>
                <small class="error-url">{{ chatUrl }}</small>
                <button class="retry-btn" @click="retryConnection">重试</button>
              </div>
            </div>
          </template>

          <!-- API 模式：直连后端 /api/AIChat/chat，自动查询本地数据库并展示 -->
          <template v-else>
            <div class="messages" ref="messagesEl">
              <div v-for="(m, idx) in messages" :key="idx" :class="['msg', m.role]">
                <div class="bubble" v-html="formatMessage(m.content)"></div>
              </div>
            </div>
            <div class="input-bar">
              <textarea
                v-model="inputText"
                :disabled="isSending"
                @keydown.enter.exact.prevent="sendMessage"
                placeholder="请输入要查询的数据，如：库存管理的数据有什么？"
              ></textarea>
              <button :disabled="isSending || !inputText.trim()" @click="sendMessage">
                <i class="bi" :class="isSending ? 'bi-hourglass-split' : 'bi-send'"></i>
              </button>
            </div>
          </template>
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'AICustomerService',
  props: {
    // 模式：'api' 通过后端SSE聊天(支持本地数据库查询)；'rag' 使用RAGFlow iframe
    mode: {
      type: String,
      default: 'api'
    },
    // 后端AI接口基础地址（用于api模式）
    apiBase: {
      type: String,
      default: 'http://localhost:9991/api/AIChat'
    },
    // RAGflow共享ID
    sharedId: {
      type: String,
      default: '42bdfaeaba4011f080667e3d45512fa6'
    },
    // 认证token
    authToken: {
      type: String,
      default: 'Y3NjMyMmJhYjNmOTExZjBiMGY2MzJhNz'
    },
    // RAGflow服务地址
    baseUrl: {
      type: String,
      default: 'http://localhost'
    },
    // 语言设置
    locale: {
      type: String,
      default: 'zh'
    }
  },
  data() {
    return {
      isOpen: false,
      isLoading: false,
      hasError: false,
      loadTimeout: null,
      // 拖拽相关
      isDragging: false,
      dragStarted: false,
      startX: 0,
      startY: 0,
      currentX: null,
      currentY: null,
      offsetX: 0,
      offsetY: 0,
      // API模式聊天状态
      messages: [
        { role: 'assistant', content: '您好！我是树哥。我已连接本地数据库，您可以直接询问：例如“库存管理的数据有什么？”、“查询产品信息”。' }
      ],
      inputText: '',
      isSending: false,
      abortController: null
    };
  },
  mounted() {
    // 从localStorage恢复位置
    const savedPosition = localStorage.getItem('ai-chat-button-position');
    if (savedPosition) {
      try {
        const { x, y } = JSON.parse(savedPosition);
        this.currentX = x;
        this.currentY = y;
      } catch (e) {
        console.error('恢复按钮位置失败:', e);
      }
    }
  },
  computed: {
    chatUrl() {
      return `${this.baseUrl}/next-chats/share?shared_id=${this.sharedId}&from=chat&auth=${this.authToken}&locale=${this.locale}`;
    },
    effectiveApiBase() {
      // 若未显式配置，则默认使用当前站点同源的后端地址
      if (!this.apiBase || this.apiBase === 'auto') {
        try {
          return `${window.location.origin}/api/AIChat`;
        } catch (e) {
          return 'http://localhost:9991/api/AIChat';
        }
      }
      return this.apiBase.replace(/\/$/, '');
    },
    buttonStyle() {
      if (this.currentX !== null && this.currentY !== null) {
        return {
          left: `${this.currentX}px`,
          top: `${this.currentY}px`,
          right: 'auto',
          bottom: 'auto'
        };
      }
      return {};
    }
  },
  methods: {
    formatMessage(text) {
      if (!text) return '';
      return text.replace(/\n/g, '<br/>');
    },
    async sendMessage() {
      const msg = this.inputText.trim();
      if (!msg || this.isSending) return;
      this.isSending = true;
      this.hasError = false;
      this.messages.push({ role: 'user', content: msg });
      this.inputText = '';
      // 预置assistant占位，流式追加
      this.messages.push({ role: 'assistant', content: '' });
      this.$nextTick(() => {
        const el = this.$refs.messagesEl;
        if (el) el.scrollTop = el.scrollHeight;
      });

      try {
        // 先做一次健康检查，提前暴露后端/RagFlow错误
        try {
          const ping = await fetch(`${this.effectiveApiBase}/health`, { method: 'GET' });
          if (!ping.ok) {
            throw new Error(`后端健康检查失败 (${ping.status})`);
          }
          try {
            const j = await ping.json();
            if (j && j.status && j.status !== 'healthy') {
              throw new Error(`AI服务状态: ${j.status}${j.statusCode ? ` (${j.statusCode})` : ''}`);
            }
          } catch(_) {}
        } catch (preErr) {
          this.messages[this.messages.length - 1].content = `连接后端失败：${preErr.message}。请确认后端端口和跨域配置；也可手动打开 ${this.effectiveApiBase}/health 查看状态。`;
          return;
        }

        this.abortController = new AbortController();
        const body = {
          message: msg,
          history: this.messages
            .slice(0, -1) // 去掉最后一个占位assistant
            .map(m => ({ Role: m.role, Content: m.content }))
        };

        const resp = await fetch(`${this.effectiveApiBase}/chat`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(body),
          signal: this.abortController.signal
        });

        if (!resp.ok || !resp.body) {
          throw new Error(`接口异常: ${resp.status}`);
        }

        const reader = resp.body.getReader();
        const decoder = new TextDecoder('utf-8');
        let assistantIdx = this.messages.length - 1;
        let done = false;
        while (!done) {
          const { value, done: streamDone } = await reader.read();
          if (streamDone) break;
          const chunk = decoder.decode(value, { stream: true });
          const lines = chunk.split(/\r?\n/).filter(l => l);
          for (const line of lines) {
            if (line.startsWith('data:')) {
              const dataStr = line.slice(5).trim();
              if (dataStr === '[DONE]') {
                done = true;
                break;
              }
              // 解析OpenAI风格增量
              try {
                const json = JSON.parse(dataStr);
                const delta = json?.choices?.[0]?.delta?.content
                  ?? json?.choices?.[0]?.message?.content
                  ?? json?.content
                  ?? '';
                if (delta) {
                  this.messages[assistantIdx].content += delta;
                }
                // 错误信息透传
                if (!delta && json?.error) {
                  this.messages[assistantIdx].content += `\n[错误] ${json.error}`;
                }
              } catch (e) {
                // 非JSON，直接追加文本
                this.messages[assistantIdx].content += (dataStr + '\n');
              }
              this.$nextTick(() => {
                const el = this.$refs.messagesEl;
                if (el) el.scrollTop = el.scrollHeight;
              });
            } else {
              // 兼容部分服务端不加 data: 前缀的行
              this.messages[assistantIdx].content += (line + '\n');
            }
          }
        }
      } catch (err) {
        console.error('聊天流式错误', err);
        this.hasError = true;
        // 失败时给出提示
        this.messages[this.messages.length - 1].content = `抱歉，服务暂时不可用：${err.message || '网络异常'}`;
      } finally {
        this.isSending = false;
        this.abortController = null;
      }
    },
    toggleChat() {
      this.isOpen = !this.isOpen;
      if (this.isOpen) {
        this.isLoading = true;
        this.hasError = false;
        // 设置超时检测（10秒后如果还在加载，显示错误）
        this.loadTimeout = setTimeout(() => {
          if (this.isLoading) {
            this.isLoading = false;
            this.hasError = true;
            console.error('RAGflow连接超时:', this.chatUrl);
          }
        }, 10000);
      } else {
        if (this.loadTimeout) {
          clearTimeout(this.loadTimeout);
        }
      }
    },
    closeChat() {
      this.isOpen = false;
      this.hasError = false;
      if (this.loadTimeout) {
        clearTimeout(this.loadTimeout);
      }
    },
    onIframeLoad() {
      console.log('RAGflow iframe加载成功');
      this.isLoading = false;
      this.hasError = false;
      if (this.loadTimeout) {
        clearTimeout(this.loadTimeout);
      }
    },
    onIframeError(error) {
      console.error('RAGflow iframe加载失败:', error);
      this.isLoading = false;
      this.hasError = true;
      if (this.loadTimeout) {
        clearTimeout(this.loadTimeout);
      }
    },
    retryConnection() {
      this.hasError = false;
      this.isLoading = true;
      // 强制重新加载iframe
      this.isOpen = false;
      this.$nextTick(() => {
        this.isOpen = true;
      });
    },
    // 鼠标拖拽事件
    handleMouseDown(e) {
      this.dragStarted = true;
      this.isDragging = false;
      
      const rect = e.currentTarget.getBoundingClientRect();
      this.offsetX = e.clientX - rect.left;
      this.offsetY = e.clientY - rect.top;
      this.startX = e.clientX;
      this.startY = e.clientY;
      
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
      
      e.preventDefault();
    },
    handleMouseMove(e) {
      if (!this.dragStarted) return;
      
      // 移动超过5px才认为是拖拽
      const deltaX = Math.abs(e.clientX - this.startX);
      const deltaY = Math.abs(e.clientY - this.startY);
      
      if (!this.isDragging && (deltaX > 5 || deltaY > 5)) {
        this.isDragging = true;
      }
      
      if (!this.isDragging) return;
      
      // 计算新位置
      let newX = e.clientX - this.offsetX;
      let newY = e.clientY - this.offsetY;
      
      // 限制在视口范围内
      const buttonWidth = 60;
      const buttonHeight = 60;
      const maxX = window.innerWidth - buttonWidth;
      const maxY = window.innerHeight - buttonHeight;
      
      newX = Math.max(0, Math.min(newX, maxX));
      newY = Math.max(0, Math.min(newY, maxY));
      
      this.currentX = newX;
      this.currentY = newY;
      
      e.preventDefault();
    },
    handleMouseUp(e) {
      document.removeEventListener('mousemove', this.handleMouseMove);
      document.removeEventListener('mouseup', this.handleMouseUp);
      
      // 如果是拖拽，保存位置
      if (this.isDragging) {
        this.savePosition();
        // 延迟重置拖拽状态，避免触发点击
        setTimeout(() => {
          this.isDragging = false;
          this.dragStarted = false;
        }, 100);
      } else {
        // 如果不是拖拽，触发点击
        this.isDragging = false;
        this.dragStarted = false;
        this.toggleChat();
      }
      
      e.preventDefault();
    },
    // 触摸拖拽事件（移动端）
    handleTouchStart(e) {
      this.dragStarted = true;
      this.isDragging = false;
      
      const touch = e.touches[0];
      const rect = e.currentTarget.getBoundingClientRect();
      this.offsetX = touch.clientX - rect.left;
      this.offsetY = touch.clientY - rect.top;
      this.startX = touch.clientX;
      this.startY = touch.clientY;
      
      document.addEventListener('touchmove', this.handleTouchMove, { passive: false });
      document.addEventListener('touchend', this.handleTouchEnd);
    },
    handleTouchMove(e) {
      if (!this.dragStarted) return;
      
      const touch = e.touches[0];
      
      // 移动超过5px才认为是拖拽
      const deltaX = Math.abs(touch.clientX - this.startX);
      const deltaY = Math.abs(touch.clientY - this.startY);
      
      if (!this.isDragging && (deltaX > 5 || deltaY > 5)) {
        this.isDragging = true;
      }
      
      if (!this.isDragging) return;
      
      // 计算新位置
      let newX = touch.clientX - this.offsetX;
      let newY = touch.clientY - this.offsetY;
      
      // 限制在视口范围内
      const buttonWidth = 60;
      const buttonHeight = 60;
      const maxX = window.innerWidth - buttonWidth;
      const maxY = window.innerHeight - buttonHeight;
      
      newX = Math.max(0, Math.min(newX, maxX));
      newY = Math.max(0, Math.min(newY, maxY));
      
      this.currentX = newX;
      this.currentY = newY;
      
      e.preventDefault();
    },
    handleTouchEnd(e) {
      document.removeEventListener('touchmove', this.handleTouchMove);
      document.removeEventListener('touchend', this.handleTouchEnd);
      
      // 如果是拖拽，保存位置
      if (this.isDragging) {
        this.savePosition();
        setTimeout(() => {
          this.isDragging = false;
          this.dragStarted = false;
        }, 100);
      } else {
        // 如果不是拖拽，触发点击
        this.isDragging = false;
        this.dragStarted = false;
        this.toggleChat();
      }
      
      e.preventDefault();
    },
    // 保存位置到localStorage
    savePosition() {
      if (this.currentX !== null && this.currentY !== null) {
        localStorage.setItem('ai-chat-button-position', JSON.stringify({
          x: this.currentX,
          y: this.currentY
        }));
      }
    }
  },
  beforeUnmount() {
    if (this.loadTimeout) {
      clearTimeout(this.loadTimeout);
    }
    if (this.abortController) {
      try { this.abortController.abort(); } catch (e) {}
    }
    // 清理事件监听
    document.removeEventListener('mousemove', this.handleMouseMove);
    document.removeEventListener('mouseup', this.handleMouseUp);
    document.removeEventListener('touchmove', this.handleTouchMove);
    document.removeEventListener('touchend', this.handleTouchEnd);
  }
};
</script>

<style scoped>
.ai-customer-service {
  position: fixed;
  z-index: 9999;
}

/* 聊天按钮样式 */
.chat-button {
  position: fixed;
  bottom: 30px;
  right: 30px;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);
  transition: all 0.3s ease;
  overflow: visible;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  touch-action: none;
  z-index: 9998;
}

.chat-button:hover {
  transform: scale(1.1);
  box-shadow: 0 6px 30px rgba(102, 126, 234, 0.6);
}

.chat-button.is-dragging {
  cursor: grabbing;
  transform: scale(1.05);
  box-shadow: 0 8px 40px rgba(102, 126, 234, 0.8);
  transition: none;
}

.chat-button:active {
  cursor: grabbing;
}

.chat-button i {
  font-size: 28px;
  position: relative;
  z-index: 2;
  pointer-events: none;
}

/* 脉冲动画 */
.pulse-ring {
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  animation: pulse 2s ease-out infinite;
  opacity: 0.6;
  pointer-events: none;
}

@keyframes pulse {
  0% {
    transform: scale(1);
    opacity: 0.6;
  }
  50% {
    transform: scale(1.3);
    opacity: 0.3;
  }
  100% {
    transform: scale(1.5);
    opacity: 0;
  }
}

/* 聊天窗口样式 */
.chat-window {
  position: fixed;
  bottom: 30px;
  right: 30px;
  width: 400px;
  height: 600px;
  background: white;
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 聊天窗口头部 */
.chat-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 16px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
}

.header-content {
  display: flex;
  align-items: center;
  gap: 10px;
}

.header-content i {
  font-size: 24px;
}

.header-title {
  font-size: 16px;
  font-weight: 600;
}

.header-actions {
  display: flex;
  gap: 8px;
}

.minimize-btn,
.close-btn {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.minimize-btn:hover,
.close-btn:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: scale(1.1);
}

.minimize-btn i,
.close-btn i {
  font-size: 16px;
}

/* 聊天内容区域 */
.chat-content {
  flex: 1;
  position: relative;
  background: #f5f5f5;
}

/* API模式消息列表 */
.messages {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 64px;
  overflow-y: auto;
  padding: 12px 12px 0 12px;
}
.msg {
  display: flex;
  margin-bottom: 10px;
}
.msg.user { justify-content: flex-end; }
.msg.assistant { justify-content: flex-start; }
.bubble {
  max-width: 78%;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.6;
  word-break: break-word;
}
.msg.user .bubble {
  background: #667eea;
  color: #fff;
  border-top-right-radius: 4px;
}
.msg.assistant .bubble {
  background: #fff;
  color: #333;
  border-top-left-radius: 4px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.06);
}
.input-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 64px;
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 8px 10px;
  background: #fff;
  border-top: 1px solid #eee;
}
.input-bar textarea {
  flex: 1;
  height: 48px;
  padding: 10px 12px;
  resize: none;
  border: 1px solid #e6e6e6;
  border-radius: 8px;
  outline: none;
}
.input-bar button {
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 10px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
  cursor: pointer;
}

.chat-iframe {
  width: 100%;
  height: 100%;
  border: none;
}

/* 加载动画 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.95);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.loading-spinner {
  text-align: center;
  color: #667eea;
}

.loading-spinner i {
  font-size: 40px;
  display: block;
  margin-bottom: 12px;
  animation: spin 1s linear infinite;
}

.loading-spinner span {
  font-size: 14px;
  color: #666;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* 错误提示 */
.error-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.98);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.error-message {
  text-align: center;
  color: #f56c6c;
  padding: 20px;
}

.error-message i {
  font-size: 50px;
  display: block;
  margin-bottom: 16px;
  color: #f56c6c;
}

.error-message p {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 12px 0;
  color: #333;
}

.error-message small {
  display: block;
  font-size: 13px;
  color: #666;
  margin-bottom: 8px;
}

.error-message .error-url {
  font-size: 11px;
  color: #999;
  word-break: break-all;
  padding: 8px;
  background: #f5f5f5;
  border-radius: 4px;
  margin-bottom: 16px;
}

.retry-btn {
  margin-top: 16px;
  padding: 10px 24px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

.retry-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}

/* 动画效果 */
.bounce-enter-active {
  animation: bounce-in 0.5s;
}

.bounce-leave-active {
  animation: bounce-out 0.3s;
}

@keyframes bounce-in {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  50% {
    transform: scale(1.1);
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes bounce-out {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}

.slide-fade-enter-active {
  animation: slide-fade-in 0.3s ease-out;
}

.slide-fade-leave-active {
  animation: slide-fade-out 0.3s ease-in;
}

@keyframes slide-fade-in {
  0% {
    transform: translateY(20px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes slide-fade-out {
  0% {
    transform: translateY(0);
    opacity: 1;
  }
  100% {
    transform: translateY(20px);
    opacity: 0;
  }
}

/* 响应式设计 */
@media (max-width: 768px) {
  .chat-window {
    width: calc(100vw - 40px);
    height: calc(100vh - 100px);
    bottom: 20px;
    right: 20px;
  }

  .chat-button {
    bottom: 20px;
    right: 20px;
    width: 56px;
    height: 56px;
  }

  .chat-button i {
    font-size: 24px;
  }
}

@media (max-width: 480px) {
  .chat-window {
    width: 100vw;
    height: 100vh;
    bottom: 0;
    right: 0;
    border-radius: 0;
  }

  .chat-button {
    bottom: 16px;
    right: 16px;
  }
}
</style>

